﻿using FlyRemote.Base;
using System;
using System.Collections.Generic;
using System.Linq;

namespace FlyRemote.Remote
{
    /// <summary>
    /// 内存扫描处理的最大单位，用来存放 读取组（输入） 和结果集（输出）  
    /// </summary>
    public class Snapshot
    {


        #region 数据 

        /// <summary>
        /// 读取组的集合
        /// </summary>
        public IList<ReadGroup> ReadGroups { get; private set; } = new List<ReadGroup>();

        /// <summary>
        /// 结果集 , 按读取组来进行分组 ,( 因为扫描是并发的 )
        /// </summary>
        public Dictionary<ReadGroup, IList<SnapshotCell>> Dict { get; private set; } = new Dictionary<ReadGroup, IList<SnapshotCell>>();

        public String SnapshotName { get; private set; }


        #endregion



        #region 构造

        public Snapshot(String snapshotName = null)
        {
            this.SnapshotName = snapshotName == null ? String.Empty : snapshotName;
        }

        public Snapshot(String snapshotName, IList<ReadGroup> memoryRegions)
        {
            this.SnapshotName = snapshotName == null ? String.Empty : snapshotName;
            this.ReadGroups = memoryRegions?.ToList();

            foreach (var u in ReadGroups)
            {

                /// 该读取组 对应一个 初始的默认结果集 
                this.Dict[u] = new List<SnapshotCell>() { new SnapshotCell(u, 0, 0) };
            }

        }

        public Snapshot(String snapshotName, Dictionary<ReadGroup, IList<SnapshotCell>> dict)
        {
            this.SnapshotName = snapshotName == null ? String.Empty : snapshotName;
            this.ReadGroups = dict.Keys.ToList();
            this.Dict = dict;

        }



        #endregion
        public void Add(ReadGroup group, IList<SnapshotCell> cells)
        {
            this.ReadGroups.Add(group);
            this.Dict[group] = cells;
        }
        public void Add(IList<SnapshotCell> cells)
        {
            this.ReadGroups.Add(cells[0].ReadGroup);
            this.Dict[cells[0].ReadGroup] = cells;
        }

        public int GroupCount { get => ReadGroups.Count; }

        /// <summary>
        /// Gets the total number of bytes contained in this snapshot.
        /// </summary>
        public UInt64 ByteCount { get; set; }

        /// <summary>
        ///获取此快照中包含的单个元素的数量。
        /// </summary>
        public Int64 ElementCount { get { Int64 count = 0; Dict.ForEach(o => count += o.Value.Count); return count; } }


        /// <summary>
        /// </summary>
        public int Alignment
        {
            set
            {
                this.ReadGroups.ForEach(readGroup => readGroup.Alignment = value);
            }
        }




        /// <summary>
        /// 获取此快照中的读组，按其区域大小降序排列。这对于多线程访问来说性能要好得多。
        /// </summary>
        public IList<ReadGroup> OptimizedReadGroups
        {
            get
            {
                try
                {

                    return this.ReadGroups?.OrderByDescending(readGroup => readGroup.RegionSize).ToList();
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }



        /// <summary>
        /// ///创建该快照的浅克隆。
        /// Creates a shallow clone of this snapshot.
        /// </summary>
        public Snapshot Clone(String newSnapshotName = null)
        {
            return new Snapshot(newSnapshotName, this.ReadGroups);
        }


        public IEnumerable<SnapshotCell> GetSnapshotElements()
        {
            if (Dict.IsNullOrEmpty())
            {
                yield return default(SnapshotCell);
            }


            foreach (var group in Dict.Keys.OrderBy(o => o.BaseAddress))
            {
                foreach (var cell in Dict[group])
                {
                    yield return cell;
                }
            }

        }



        #region

        // 读取方法 , 
        // 不能设计在 ReadGroup , 粒度太小, 无法命中 
        public object Read(DataType dataType, ulong address, out bool success)
        {
            success = false;
            foreach (var group in this.ReadGroups)
            {
                if (group.BaseAddress <= address && address < group.EndAddress)
                {
                    if (group.CurrentValues != null)
                    {
                        success = true;
                        return null;
                        //return dataType.FromBytes(group.CurrentValues, (int)(address - group.BaseAddress));
                    }

                    return null;
                }
            }


            return null;
        }

        public ReadGroup GetReadGroup(ulong address)
        {
            foreach (var group in this.ReadGroups)
            {
                if (group.BaseAddress <= address && address < group.EndAddress)
                {
                    return group;
                }
            }

            return null;
        }

        #endregion



        #region 读取组合并


        //private IList<IRefreshable> mergedgroups;

        ///// <summary>
        ///// 进行连续合并后的读取组 
        ///// </summary>
        //private IList<IRefreshable> MergedGroups { get { if (mergedgroups == null) mergedgroups = GetReadCells(); return mergedgroups; } }

        //private IList<IRefreshable> GetReadCells()
        //{

        //    List<IRefreshable> list = new List<IRefreshable>();


        //    var ordered = ReadGroups.OrderBy(o => o.BaseAddress).ToList();


        //    for (int i = 0; i < ordered.Count; i++)
        //    {

        //        // 最后一个，肯定没有连续
        //        if (i == ordered.Count - 1)
        //        {
        //            list.Add(ordered[i]);
        //            break;
        //        }

        //        // 出现了连续 
        //        if (ordered[i].EndAddress == ordered[i + 1].BaseAddress)
        //        {
        //            ReadCell cell = new ReadCell();
        //            for (; i < ordered.Count - 1 && ordered[i].EndAddress == ordered[i + 1].BaseAddress; i++)
        //            {
        //                cell.Groups.Add(ordered[i]);
        //            }
        //            cell.Groups.Add(ordered[i]);
        //            list.Add(cell);

        //        }
        //        else
        //        {
        //            list.Add(ordered[i]);
        //        }



        //    }


        //    /// 目前是按地址 从小到大 的顺序 
        //    /// 感觉不排序，反而更快

        //    return list/*.OrderBy(o=> o.RegionSize).ToList()*/ ;
        //}



        #endregion


    }

}
